package com.example.backspring.Service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.backspring.Service.LearnService;
import com.example.backspring.config.Message;
import com.example.backspring.config.SnowflakeSixDigits;
import com.example.backspring.dao.FuxiMapper;
import com.example.backspring.dao.LearnMapper;
import com.example.backspring.entity.Fuxi;
import com.example.backspring.entity.Learn;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Slf4j
@Service
public class LearnServiceImpl implements LearnService {
    @Resource
    private FuxiMapper fuxiMapper;
    @Resource
    private LearnMapper learnMapper;

    /**
     * 添加学习计划及复习计划
     *
     * @param nr 要添加的学习内容
     * @return 包含操作结果的Message对象
     *
     * 此方法首先生成当前时间作为学习时间，并定义了一系列复习时间间隔常量（一天、两天、六天、三十天）。
     * 然后，为学习内容生成一个基于雪花算法的唯一ID（取其后六位作为整数ID）。
     * 接下来，尝试将学习内容和复习计划添加到数据库中。学习计划直接添加，而复习计划则根据定义的时间间隔多次添加。
     * 如果所有操作都成功完成，将返回一个表示成功的Message对象；否则，返回一个表示失败的Message对象。
     * 在操作过程中，如果遇到任何异常，将捕获该异常并记录错误日志，然后返回一个表示系统错误的Message对象。
     */
    @Override
    public Message addLearn(String nr) {
        String xueTime = getDate(0, "f");
        // 定义复习时间间隔常量
        final int ONE_DAY = 1;
        final int TWO_DAYS = 2;
        final int SIX_DAYS = 6;
        final int THIRTY_DAYS = 30;

        // 复习计划时间
        String yiTimer = getDate(ONE_DAY, "f");
        String erTimer = getDate(TWO_DAYS, "f");
        String liuTimer = getDate(SIX_DAYS, "f");
        String sanyaoTimer = getDate(THIRTY_DAYS, "f");

        Message result = new Message();
        int status = 0; // 使用更有意义的变量名代替 pod
        SnowflakeSixDigits snowflake = new SnowflakeSixDigits();
        long idwoq = snowflake.nextId();
        long l = idwoq % 100000000; // 取后六位数字
        int id = Integer.parseInt(String.valueOf(l));

        try {
            // 添加学习计划
            Integer res = learnMapper.addnr(id, xueTime, nr, status);
            // 添加复习计划
            fuxiMapper.addnr(id, yiTimer, nr, status);
            fuxiMapper.addnr(id + 1, erTimer, nr, status);
            fuxiMapper.addnr(id + 2, liuTimer, nr, status);
            fuxiMapper.addnr(id + 3, sanyaoTimer, nr, status);

            if (res == 1) {
                result.setSuccess(true);
                result.setMessage("添加学习计划成功");
                result.setStatus(Message.SUCCESS_STATUS); // 假设Message类定义了SUCCESS_STATUS常量
            } else {
                result.setSuccess(false);
                result.setMessage("添加失败");
                result.setStatus(Message.FAIL_STATUS); // 假设Message类定义了FAIL_STATUS常量
            }
        } catch (Exception e) {
            log.error("添加学习或复习计划时发生异常", e);
            result.setSuccess(false);
            result.setMessage("系统错误，请稍后再试");
            result.setStatus(Message.FAIL_STATUS);
        }

        return result;
    }


    /**
     * 标记学习完成，并尝试添加复习计划
     *
     * @param id 要标记为已完成的学习内容的ID
     * @return 包含操作结果的Message对象
     *
     * 通过传入的学习内容ID，调用learnMapper的gaiStatus方法尝试更新该学习内容的状态，并尝试为其添加复习计划。
     * 如果更新状态成功，则返回表示成功的Message对象，其中消息为"添加复习计划成功"，状态码为1。
     * 如果更新状态失败，则返回表示失败的Message对象，其中消息为"添加失败"，状态码为0。
     */
    @Override
    public Message learnDone(Integer id) {
        Message result = new Message();
        Integer res = learnMapper.gaiStatus(id);
        if (res == 1) {
            result.setSuccess(true);
            result.setMessage("添加复习计划成功");
            result.setStatus(1);
        } else {
            result.setSuccess(false);
            result.setMessage("添加失败");
            result.setStatus(0);
        }
        return result;
    }

    /**
     * 获取已完成的学习数据
     *
     * @return 包含已完成的学习数据的Message对象
     *
     * 此方法用于获取数据库中已完成的学习数据。首先，通过learnMapper的getnr方法获取所有已完成的学习记录。
     * 如果获取到的学习记录不为空，则遍历每一条记录，将其中的学习内容（nr）和学习时间（sj）转换为字符串，并存储到JSONObject中。
     * 将所有JSONObject对象添加到JSONArray中，作为Message对象的数据部分返回。同时，设置Message对象的成功标志为true，状态码为1。
     * 如果获取到的学习记录为空，则设置Message对象的成功标志为false，消息内容为"暂无学习数据"，状态码为0。
     * 最后，返回包含操作结果的Message对象。
     */
    @Override
    public Message getXuewan() {
        Message result = new Message();
        JSONArray data = new JSONArray();
        List<Learn> res = learnMapper.getnr();
        if (res.size() > 0) {
            for (Learn learn : res) {
                JSONObject map = new JSONObject();
                map.put("nr", learn.getNr().toString());
                map.put("sj", learn.getSj().toString());
                data.add(map);
            }
            result.setMessage(data);
            result.setSuccess(true);
            result.setStatus(1);
        } else {
            result.setSuccess(false);
            result.setMessage("暂无学习数据");
            result.setStatus(0);
        }
        return result;
    }

    /**
     * 将List集合转换为JSONArray对象
     *
     * @param list 需要转换的List集合，集合中的元素类型可以是Learn或Fuxi类型或其子类
     * @return 转换后的JSONArray对象，包含了List集合中每个元素的"nr"和"sj"字段值，其中"nr"字段值为Learn或Fuxi对象的nr属性值，
     *         "sj"字段值为Learn或Fuxi对象的sj属性值的字符串形式
     * @throws ClassCastException 如果List集合中的元素类型既不是Learn也不是Fuxi或其子类，则会抛出ClassCastException异常
     */
    private JSONArray convertToJsonArray(List<? extends Object> list) {
        JSONArray jsonArray = new JSONArray();
        if (!list.isEmpty()) {
            for (Object obj : list) {
                // 假设有一个共通的接口或父类提供getNr和getSj方法
                Map<String, Object> map = new HashMap<>();
                map.put("nr", obj instanceof Learn ? ((Learn)obj).getNr() : ((Fuxi)obj).getNr());
                map.put("sj", obj instanceof Learn ? ((Learn)obj).getSj().toString() : ((Fuxi)obj).getSj().toString());
                // 如果Learn和Fuxi类有共同的ID字段，也可以添加
                // map.put("id", obj.getId());
                jsonArray.add(map);
            }
        }
        return jsonArray;
    }
    /**
     * 获取复习数据
     *
     * @return 包含复习数据的Message对象
     *
     * 该方法首先获取当前日期（格式化为"j"格式），然后调用fuxiMapper的getnr方法根据当前日期获取复习数据列表。
     * 将获取到的复习数据列表转换为JSONArray对象，并存储在data变量中。
     * 如果data不为空，则将data设置为Message对象的消息内容，并将成功标志设置为true，状态码设置为SUCCESS_STATUS（假设Message类中已定义此常量）。
     * 如果data为空，则将成功标志设置为false，消息内容设置为"暂无复习数据"，状态码设置为FAIL_STATUS（假设Message类中已定义此常量）。
     * 最后，将当前日期和复习数据量记录到日志中，并返回包含结果的Message对象。
     */
    @Override
    public Message getFuxi() {
        String currentDate = getCurrentDate("j"); // 变量名改为更清晰的 currentDate
        List<Fuxi> fuxiList = fuxiMapper.getnr(currentDate);
        JSONArray data = convertToJsonArray(fuxiList);

        Message result = new Message();
        if (!data.isEmpty()) {
            result.setMessage(data);
            result.setSuccess(true);
            result.setStatus(result.SUCCESS_STATUS); // 假设Message类中有明确的成功状态常量
        } else {
            result.setSuccess(false);
            result.setMessage("暂无复习数据");
            result.setStatus(result.FAIL_STATUS); // 假设Message类中有明确的失败状态常量
        }

        // 日志记录包含更详细的信息
        log.info("时间：{} \t\t结果：获取复习数据 - 数据量：{}", currentDate, fuxiList.size());
        return result;
    }

    /**
     * 追加学习计划内容
     *
     * @param nr 要追加的学习计划内容
     * @return 包含操作结果的Message对象
     *
     * 该方法首先获取当前日期，并根据当前日期获取对应的学习计划ID。如果未找到对应的学习计划ID，则返回包含失败信息的Message对象。
     * 接下来，构造一个包含学习计划ID及其后三个ID的列表，用于更新学习计划内容和复习计划内容。
     * 遍历该列表，对于每个ID，分别调用learnMapper的updatenr方法和fuxiMapper的updatenr方法更新学习计划内容和复习计划内容。
     * 如果所有更新操作都成功完成，则记录成功日志，并返回包含成功信息的Message对象。
     * 如果在更新过程中发生任何失败，则记录失败日志，并返回包含失败信息的Message对象。
     * 如果在执行过程中发生异常，则捕获异常并记录错误日志，返回包含系统错误信息的Message对象。
     */
    @Override
    public Message zuijia(String nr) {
        try {
            String sj = getCurrentDate("j");
            Integer id = learnMapper.huoId(sj);
            if (id == null) {
                return new Message(false, "未找到对应的学习计划ID", 0);
            }

            List<Integer> idsToUpdate = Arrays.asList(id, id + 1, id + 2, id + 3);
            boolean updateSuccess = true;
            learnMapper.updatenr(id, nr);
            for (Integer updateId : idsToUpdate) {
                if (fuxiMapper.updatenr(updateId, nr) <= 0) {
                    updateSuccess = false;
                    break;
                }
            }

            if (updateSuccess) {
                log.info("修改内容成功");
                return new Message(true, "追加成功", 1);
            } else {
                return new Message(false, "追加失败", 0);
            }
        } catch (Exception e) {
            log.error("追加学习计划时发生异常", e);
            return new Message(false, "系统错误，请稍后再试", 0);
        }
    }

    /**
     * 根据指定的格式获取当前日期和时间。
     *
     * @param format 格式字符串，如果为"j"则返回格式为"MM-dd"的日期，否则返回格式为"MM-dd HH:mm"的日期和时间。
     * @return 根据指定格式返回的当前日期或日期时间字符串。
     */
    // 修改getDate方法为两个方法，分别获取当前日期和格式化日期
    private String getCurrentDate(String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format.equals("j") ? "MM-dd" : "MM-dd HH:mm");
        return LocalDateTime.now().format(formatter);
    }


    /**
     * 将Learn对象列表转换为JSONArray格式
     *
     * @param res Learn对象列表
     * @return 包含Learn对象信息的JSONArray
     */
    public JSONArray zhuan(List<Learn> res) {
        JSONArray jsonArray = new JSONArray();
        for (Learn obj : res) {
            Map<String, Object> map = new HashMap<>();
            map.put("nr", obj.getNr());
            map.put("sj", obj.getSj().toString());
            // 使用Learn对象自己的ID，假设Learn类中有一个getId()方法
            map.put("id", obj.getId());
            jsonArray.add(map);
        }
        return jsonArray;
    }


    /**
     * 根据给定的天数偏移量和日期格式，返回偏移后的日期字符串
     *
     * @param duoshao 天数偏移量，正数表示未来，负数表示过去
     * @param jOrF    日期格式，'j' 表示 "MM-dd"，其他值表示 "MM-dd HH:mm"
     * @return 偏移后的日期字符串
     */
    public static String getDate(int duoshao, String jOrF) {
        final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
        SimpleDateFormat formatter;
        if ("j".equals(jOrF)) {
            // 显示年月日
            formatter = new SimpleDateFormat("yyyy-MM-dd");
        } else {
            // 显示年月日时分秒
            formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }

        long yiTimeInMillis = System.currentTimeMillis();
        if (duoshao == 1) {
            yiTimeInMillis += ONE_DAY_IN_MILLIS;
        } else if (duoshao == 2) {
            yiTimeInMillis += 2 * ONE_DAY_IN_MILLIS;
        } else if (duoshao == 6) {
            yiTimeInMillis += 6 * ONE_DAY_IN_MILLIS;
        } else if (duoshao == 30) {
            java.util.Calendar calendar = java.util.Calendar.getInstance();
            calendar.setTimeInMillis(yiTimeInMillis);
            calendar.add(java.util.Calendar.DAY_OF_MONTH, 30);
            // 注意：如果需求是严格增加一个月，应使用 calendar.add(Calendar.MONTH, 1);
            yiTimeInMillis = calendar.getTimeInMillis();
        } else if (duoshao == -1) {
            yiTimeInMillis -= ONE_DAY_IN_MILLIS;
        }

        Date yiTime = new Date(yiTimeInMillis);
        return formatter.format(yiTime);
    }

}
